# coding=UTF-8
import os

from common.enums.Enums import FormCons
from utils import json_util, statisticalutil


def parse_x(data_list, val_key):
    x = []
    for data in data_list:
        x.append(data[val_key])
    return x


def parse_x_reverse(data_list: list, val_key):
    x = []
    length = len(data_list)
    for i in range(length):
        x.append(data_list[length - 1 - i][val_key])
    return x


# 三个数值的形态
def thr_form(x):
    if len(x) != 3:
        return '....'
    if x[0] > x[1] > x[2]:
        return '/'
    if x[0] < x[1] < x[2]:
        return '\\'
    if x[0] >= x[1] and x[1] <= x[2]:
        return 'v'
    if x[0] <= x[1] and x[1] >= x[2]:
        return '^'
    print('数据异常' + str(x))
    return '---'


# 两个数值和零轴的形态
def zero_form(x1, x2):
    if x1 > 0 and x2 > 0:
        return 'L'
    if x1 < 0 and x2 < 0:
        return 'T'
    if x1 > 0 and x2 < 0:
        return '/'
    if x1 < 0 and x2 > 0:
        return '\\'
    print('数据异常' + str(x1) + ':' + str(x2))
    return '--'


# 获取一个最高分
def get_highest_score(form_dict):
    highest = -1
    form = ''
    for key in form_dict.keys():
        score = form_dict[key]['score']
        if score >= highest:
            highest = score
            form = key
    return form_dict[form]


# 使用默认配置的 front
def exam_all_form(x):
    form_dict = {
        '/': {'form': '/', 'score': 0, 'front': 0, 'amplitude': 15},
        '\\': {'form': '\\', 'score': 0, 'front': 0, 'amplitude': 15},
        'L': {'form': 'L', 'score': 0, 'front': 50, 'amplitude': 15},
        '厂': {'form': '厂', 'score': 0, 'front': 70, 'amplitude': 15},
        'V': {'form': 'V', 'score': 0, 'front': 50, 'amplitude': 10},
        'n': {'form': 'n', 'score': 0, 'front': 50, 'amplitude': 10},
        'hj': {'form': 'hj', 'score': 0, 'front': 50, 'amplitude': 10},
        'hs': {'form': 'hs', 'score': 0, 'front': 50, 'amplitude': 10},
        'h': {'form': 'h', 'score': 0, 'front': 50, 'amplitude': 10},
    }
    size = len(x)
    if size < 3:
        return form_dict
    max = x[0]
    min = x[0]
    for i in range(1, size):
        if max < x[i]:
            max = x[i]
        if min > x[i]:
            min = x[i]
    for subjects in form_dict.keys():
        form_info = form_dict[subjects]
        if amplitude_check(min, max, form_info['amplitude']) == 0:
            continue
        if subjects == 'L':
            form_info['score'] = exam_l_form(x, min, max, form_info['front'])
        elif subjects == '厂':
            form_info['score'] = exam_chang_form(x, min, max, form_info['front'])
        elif subjects == 'V':
            form_info['score'] = exam_v_form(x, min, max, form_info['front'])
        elif subjects == 'n':
            form_info['score'] = exam_n_form(x, min, max, form_info['front'])
        elif subjects == '\\':
            form_info['score'] = exam_down_form(x, min, max)
        elif subjects == '/':
            form_info['score'] = exam_up_form(x, min, max)
        form_dict[subjects] = form_info
    return form_dict


# 形态测试
# x 数列（最小长度为3）
# front前一段站百分比（就是一竖站总长百分比）
# amplitude 振幅 > 0 为大于当前振奋 <0 为小于当前振奋 按照总长100计算
# subjects 考试科目
def exam_form_score(x, front: int, amplitude: int, subjects: str) -> float:
    size = len(x)
    if size < 3:
        return 0
    max_v = x[0]
    min_v = x[0]
    for i in range(1, size):
        max_v = max(max_v, x[i])
        min_v = min(min_v, x[i])
    if amplitude_check(min_v, max_v, amplitude) == 0:
        return 0
    if subjects == 'L':
        return exam_l_form(x, min_v, max_v, front)
    elif subjects == '厂':
        return exam_chang_form(x, min_v, max_v, front)
    elif subjects == 'V':
        return exam_v_form(x, min_v, max_v, front)
    elif subjects == 'n':
        return exam_n_form(x, min_v, max_v, front)
    elif subjects == '\\':
        return exam_down_form(x, min_v, max_v)
    elif subjects == '/':
        return exam_up_form(x, min_v, max_v)
    else:
        return 0


# 振幅检查
# amplitude 振幅 > 0 为大于当前振奋 <0 为小于当前振奋 按照总长100计算
def amplitude_check(min, max, amplitude):
    rise_prop = round((max - min) / min, 4) * 100
    if amplitude > 0 and rise_prop < amplitude or amplitude < 0 and rise_prop > (-amplitude):
        return 0
    return 1


# L形态测试
# x 数列（最小长度为3）
# min 数列最大值
# max 数列最小值
# front前一段站百分比
def exam_l_form(x, min, max, front):
    size = len(x)
    compare_params = []
    compare_size = round(size * front / 100)
    diff_p = round((max - min) / compare_size, 4)
    param = max
    compare_params.append(param)
    for i in range(size - 1):
        if i < compare_size:
            param -= diff_p
        compare_params.append(param)
    return round(statisticalutil.correlation(x, compare_params), 4)


# 厂形态测试
# x 数列（最小长度为3）
# min 数列最大值
# max 数列最小值
# front前一段站百分比
def exam_chang_form(x, min, max, front):
    size = len(x)
    compare_params = []
    compare_size = round(size * front / 100)
    diff_p = round((max - min) / compare_size, 4)
    param = min
    compare_params.append(param)
    for i in range(size - 1):
        if i < compare_size:
            param += diff_p
        compare_params.append(param)
    return round(statisticalutil.correlation(x, compare_params), 4)


# V形态测试
# x 数列（最小长度为3）
# min 数列最大值
# max 数列最小值
# front前一段站百分比
def exam_v_form(x, min, max, front):
    size = len(x)
    compare_params = []
    compare_size = round(size * front / 100) - 1
    diff_p = round((max - min) / compare_size, 4)
    param = max
    compare_params.append(param)
    for i in range(size - 1):
        if i < compare_size:
            param -= diff_p
        else:
            param += diff_p
        compare_params.append(param)
    return round(statisticalutil.correlation(x, compare_params), 4)


# n形态测试
# x 数列（最小长度为3）
# min 数列最大值
# max 数列最小值
# front前一段站百分比
def exam_n_form(x, min, max, front):
    size = len(x)
    compare_params = []
    compare_size = round(size * front / 100) - 1
    diff_p = round((max - min) / compare_size, 4)
    param = min
    compare_params.append(param)
    for i in range(size - 1):
        if i < compare_size:
            param += diff_p
        else:
            param -= diff_p
        compare_params.append(param)
    return round(statisticalutil.correlation(x, compare_params), 4)


# \形态测试
# x 数列（最小长度为3）
# min 数列最大值
# max 数列最小值
# front前一段站百分比
def exam_down_form(x, min, max):
    size = len(x)
    compare_params = []
    diff_p = round((max - min) / (size - 1), 4)
    param = max
    compare_params.append(param)
    for i in range(size - 1):
        param -= diff_p
        compare_params.append(param)
    return round(statisticalutil.correlation(x, compare_params), 4)


# /形态测试
# x 数列（最小长度为3）
# min 数列最大值
# max 数列最小值
# front前一段站百分比
def exam_up_form(x, min, max):
    size = len(x)
    compare_params = []
    diff_p = round((max - min) / (size - 1), 4)
    param = min
    compare_params.append(param)
    for i in range(size - 1):
        param += diff_p
        compare_params.append(param)
    return round(statisticalutil.correlation(x, compare_params), 4)


# todo 扩展 N 形态 和 s形态

# 判断数列形态
# 分数小于0.5的不做参考
def judge_form(x):
    form_dict = {}
    size = len(x)
    max = x[0]
    min = x[0]
    sum = x[0]
    for i in range(1, size):
        if max < x[i]:
            max = x[i]
        if min > x[i]:
            min = x[i]
        sum += x[i]

    # 上升形态 '/'
    param = min
    compare_params = []
    compare_params.append(param)
    diff_param = round((max - min) / size, 4)
    for i in range(size - 1):
        param = param + diff_param
        compare_params.append(param)
    form_dict['/'] = round(statisticalutil.correlation(x, compare_params), 4)
    # 下降形态 '\\'
    param = max
    compare_params = []
    compare_params.append(param)
    diff_param = round((max - min) / size, 4)
    for i in range(size - 1):
        param = param - diff_param
        compare_params.append(param)
    form_dict['\\'] = round(statisticalutil.correlation(x, compare_params), 4)
    # 形态 'v'
    param = max
    compare_params = []
    compare_params.append(param)
    compare_size = int(size / 2)
    diff_param = round((max - min) / compare_size, 4)
    for i in range(size - 1):
        if i < compare_size:
            param = param - diff_param
        else:
            param = param + diff_param
        compare_params.append(param)
    form_dict['v'] = round(statisticalutil.correlation(x, compare_params), 4)
    # 形态 '^'
    param = min
    compare_params = []
    compare_params.append(param)
    compare_size = int(size / 2)
    diff_param = round((max - min) / compare_size, 4)
    for i in range(size - 1):
        if i < compare_size:
            param = param + diff_param
        else:
            param = param - diff_param
        compare_params.append(param)
    form_dict['^'] = round(statisticalutil.correlation(x, compare_params), 4)
    score = 0
    score_key = ''
    for key in form_dict.keys():
        if score < form_dict[key]:
            score = form_dict[key]
            score_key = key
    # 形态 'N'
    param = min
    compare_params = []
    compare_params.append(param)
    compare_size = int(size / 3)
    diff_param = round((max - min) / compare_size, 4)
    for i in range(size - 1):
        if i < compare_size:
            param = param + diff_param
        elif i < compare_size * 2:
            param = param - diff_param
        else:
            param = param + diff_param
        compare_params.append(param)
    form_dict['N'] = round(statisticalutil.correlation(x, compare_params), 4)

    # 形态 's'
    param = max
    compare_params = []
    compare_params.append(param)
    compare_size = int(size / 3)
    diff_param = round((max - min) / compare_size, 4)
    for i in range(size - 1):
        if i < compare_size:
            param = param - diff_param
        elif i < compare_size * 2:
            param = param + diff_param
        else:
            param = param - diff_param
        compare_params.append(param)
    form_dict['s'] = round(statisticalutil.correlation(x, compare_params), 4)
    print(form_dict)
    score = 0
    score_key = ''
    for key in form_dict.keys():
        if score < form_dict[key]:
            score = form_dict[key]
            score_key = key
    return {score_key: score}


# 生成一个x数列
def gen_x(list_info, key):
    x = []
    for info in list_info:
        x.append(float(json_util.info_to_json(info)[key]))
    return x


# 判断数列形态
# 分数小于0.5的不做参考
# ex_form:期望的形态
def judge_form_expect(x, ex_form):
    size = len(x)
    if size < 4:
        return 0
    max = x[0]
    min = x[0]
    sum = x[0]
    for i in range(1, size):
        if max < x[i]:
            max = x[i]
        if min > x[i]:
            min = x[i]
        sum += x[i]
    score = 0
    if ex_form == '厂':  # 厂形态7:3形态
        rise_prop = round((max - min) / min, 4) * 100
        if rise_prop < 15:  # 没有15的涨幅不考虑
            return 0
        compare_params = []
        compare_size = round(size * 7 / 10)  # 四舍五入
        diff_p = round((max - min) / compare_size, 4)
        param = min
        compare_params.append(param)
        for i in range(size - 1):
            if i < compare_size:
                param += diff_p
            compare_params.append(param)
        score = round(statisticalutil.correlation(x, compare_params), 4)
    if ex_form == 'L':  # L形态7:3形态
        rise_prop = round((max - min) / min, 4) * 100
        if rise_prop < 15:  # 没有15的涨幅不考虑
            return 0
        compare_params = []
        compare_size = round(size * 7 / 10)  # 四舍五入
        diff_p = round((max - min) / compare_size, 4)
        param = min
        compare_params.append(param)
        for i in range(size - 1):
            if i < compare_size:
                param += diff_p
            compare_params.append(param)
        score = round(statisticalutil.correlation(x, compare_params), 4)

    return score


# 取三条macd判断形态
# macd  负连续往下 -\\ 不考虑和卖出
# macd  负连续往上 -// 买入
# macd  负连上拐  -\/  买入信号
# macd  负连下拐  -/\  卖出
# macd  正连续往下 \\ 不考虑和卖出
# macd  正连续往上 // 持有
# macd  正连上拐  \/  买入信号
# macd  正连下拐  /\  卖出
def form_thr(x):
    if len(x) != 3:
        return ''
    x0 = float(x[0])  # 最新日期
    x1 = float(x[1])
    x2 = float(x[2])
    if x0 > x1 and x1 > x2:
        return '/'
    if x0 < x1 and x1 < x2:
        return '\\'
    if x0 >= x1 and x1 <= x2:
        return 'v'
    if x0 <= x1 and x1 >= x2:
        return '^'


class FormInfo:
    def __init__(self):
        self.zf: float = 0  # 振幅
        self.max_score: float = 0  # 最高评分
        self.max_front: float = 0  # 最高评分前比例
        self.best_form: str = ''  # 最佳运行模型

    def __repr__(self):
        return repr((self.zf, self.max_score, self.max_front, self.best_form))


# 获取最佳形态
def get_best_form(x: list) -> FormInfo:
    form_info = FormInfo()
    size = len(x)
    if size < 3:
        return form_info
    max_v = x[0]
    min_v = x[0]
    for i in range(1, size):
        max_v = max(max_v, x[i])
        min_v = min(min_v, x[i])
    form_info.zf = round((max_v - min_v) / min_v * 100, 2)
    up_score = exam_up_form(x, min_v, max_v)
    form_info.max_score = up_score
    form_info.max_front = 0
    cir = min(size, 50)
    if up_score > 0:  # 总体属于升的状态
        form_info.best_form = FormCons.s
    else:
        form_info.best_form = FormCons.j
    for i in range(1, cir):
        sore_v = exam_v_form(x, min_v, max_v, int((i + 1) / cir * 100))
        if sore_v > form_info.max_score:
            form_info.max_score = sore_v
            form_info.max_front = int((i + 1) / cir * 100)
            form_info.best_form = FormCons.js
    if form_info.max_score > 0.9:
        return form_info
    for i in range(1, cir):
        sore_n = exam_n_form(x, min_v, max_v, int((i + 1) / cir * 100))
        if sore_n > form_info.max_score:
            form_info.max_score = sore_n
            form_info.max_front = int((i + 1) / cir * 100)
            form_info.best_form = FormCons.sj
    if form_info.max_score > 0.9:
        return form_info
    if form_info.max_score < 0.5 and form_info.best_form == FormCons.sj:
        # 测试厂（sh）和7(hs)形态
        for i in range(1, cir - 1):
            score_chang = exam_chang_form(x, min_v, max_v, int((i + 1) / cir * 100))
            if score_chang > form_info.max_score:
                form_info.max_score = score_chang
                form_info.max_front = form_info.max_front + i
                form_info.best_form = FormCons.sh
        if form_info.max_score > 0.9:
            return form_info
        for i in range(1, cir - 1):
            score_hj = exam_hj_form(x, min_v, max_v, int((i + 1) / cir * 100))
            if score_hj > form_info.max_score:
                form_info.max_score = score_hj
                form_info.max_front = form_info.max_front + i
                form_info.best_form = FormCons.hj
        if form_info.max_score > 0.9:
            return form_info
    if form_info.max_score < 0.5 and form_info.best_form == FormCons.js:
        # 测试L（sh）和7(hs)形态
        for i in range(1, cir - 1):
            score_l = exam_l_form(x, min_v, max_v, int((i + 1) / cir * 100))
            if score_l > form_info.max_score:
                form_info.max_score = score_l
                form_info.max_front = form_info.max_front + i
                form_info.best_form = FormCons.jh
        if form_info.max_score > 0.9:
            return form_info
        for i in range(1, cir - 1):
            score_hs = exam_hs_form(x, min_v, max_v, int((i + 1) / cir * 100))
            if score_hs > form_info.max_score:
                form_info.max_score = score_hs
                form_info.max_front = form_info.max_front + i
                form_info.best_form = FormCons.hs
        if form_info.max_score > 0.9:
            return form_info
    return form_info


# hj(7)形态测试
def exam_hj_form(x, min_v, max_v, front):
    size = len(x)
    compare_params = []
    compare_size = round(size * (100 - front) / 100)
    step_len = round((max_v - min_v) / compare_size, 4)
    param = max_v
    compare_params.append(param)
    for i in range(size - 1):
        if i >= compare_size:
            param -= step_len
        compare_params.append(param)
    return round(statisticalutil.correlation(x, compare_params), 4)


# hs(j)形态测试
def exam_hs_form(x, min_v, max_v, front):
    size = len(x)
    compare_params = []
    compare_size = round(size * (100 - front) / 100)
    if compare_size == 0:
        return 0
    step_len = round((max_v - min_v) / compare_size, 4)
    param = min_v
    compare_params.append(param)
    for i in range(size - 1):
        if i >= compare_size:
            param += step_len
        compare_params.append(param)
    return round(statisticalutil.correlation(x, compare_params), 4)


# n形态测试
# x 数列（最小长度为3）
# min 数列最大值
# max 数列最小值
# front前一段站百分比
def exam_best_form(x, min, max, front):
    size = len(x)
    compare_params = []
    compare_size = round(size * front / 100) - 1
    diff_p = round((max - min) / compare_size, 4)
    param = min
    compare_params.append(param)
    for i in range(size - 1):
        if i < compare_size:
            param += diff_p
        else:
            param -= diff_p
        compare_params.append(param)
    return round(statisticalutil.correlation(x, compare_params), 4)


if __name__ == '__main__':
    # s1 = exam_form_score([6, 5, 4, 3, 2, 1, 2, 3, 4, 5], 60, 400, 'V')
    # s4 = exam_form_score([6, 5, 4, 3, 2, 1, 2, 3, 4, 5], 60, 400, 'n')
    # s2 = exam_form_score([8, 7, 6, 5, 4, 3, 2, 1, 1, 1], 70, 400, 'L')
    # s3 = exam_form_score([1, 2, 3, 4, 5, 6, 7, 7, 7, 7], 60, 400, '厂')
    # s5 = exam_form_score([9, 8, 7, 6, 5, 4, 3, 2, 1], 0, 400, '\\')
    # s6 = exam_form_score([9, 8, 7, 6, 5, 4, 3, 2, 1], 0, 400, '/')
    # s7 = exam_form_score([1, 2, 3, 4, 5, 6, 7, 8, 9], 0, 400, '/')
    # form_info = get_best_form([1, 2, 3, 4, 5, 6, 7, 8, 9])
    # form_info = get_best_form([1, 2, 3, 2, 1, 2, 3, 2, 1, 2, 3])
    form_info = get_best_form([1.01, 1.02, 1.03, 1.04, 1.05, 1.06, 1.07, 1.08, 1.07, 1.06, 1.05, 1.04])
    print(form_info.__dict__)
